package com.huoshan.im.server;


import com.huoshan.im.server.dto.UserDto;
import com.huoshan.im.server.messaging.MessageId;
import lombok.extern.slf4j.Slf4j;
import online.chazi.netkit.NetkitContext;
import online.chazi.netkit.Session;
import online.chazi.netkit.SessionGroup;
import online.chazi.netkit.messaging.Message;

import java.util.Collection;
import java.util.Objects;

/**
 * 说明：作者很懒，什么都没留下
 * Created by 火山九日 on 2020-04-26 10:51
 */
@Slf4j
public class SessionHolder {

    //保存所有用户的session
    private static final SessionGroup ALL_USER_SESSIONS = new SessionGroup(false); //设置为手工处理关闭的连接
    // 保存系统session
    private static final SessionGroup ALL_SYSTEM_SESSIONS = new SessionGroup();
    // 保存repeater的session
    private static final SessionGroup ALL_REPEATER_SESSIONS = new SessionGroup();

    private static NetkitContext CONTEXT;

    public static NetkitContext getContext() {
        return CONTEXT;
    }

    protected static void buildNetkitContext(int core) {
        if (CONTEXT == null)
            CONTEXT = new NetkitContext(core);
        else throw new IllegalArgumentException("不能修改CONTEXT！");
    }

    public static void addUserSession(UserDto userDto, Session session) {
        // 判断是否有已经在线的session,挤下线
        Session oldSession = getUserSession(userDto);

        log.info("session group size = {} ", ALL_USER_SESSIONS.size());

        if (oldSession != null && !Objects.equals(session.getSessionId().asLongText(), oldSession.getSessionId().asLongText())) {
            log.info("已经在线的session,挤下线,userDto={}", userDto);

            removeUserSession(userDto);

            ALL_USER_SESSIONS.add(userDto.toString(), session);

            Message logoutMessage = new Message(MessageId.SYS_KICK_USER_OFFLINE.id);
            oldSession.sendMessageAndClose(logoutMessage);

            //removeUserSession(userDto); 已经关闭了之前的链接，那么这个时候，不需要再去移除连接了
        } else {
            ALL_USER_SESSIONS.add(userDto.toString(), session);
        }

    }

    /**
     * @param userDto
     * @return
     */
    public static Session getUserSession(UserDto userDto) {
        return ALL_USER_SESSIONS.get(userDto.toString());
    }

    /**
     * @param userId
     * @param clientType
     * @return
     */
    public static Session getUserSession(long userId, String clientType) {
        UserDto userDto = new UserDto(userId, clientType);
        return ALL_USER_SESSIONS.get(userDto.toString());
    }


    public static void removeUserSession(UserDto userDto) {
        ALL_USER_SESSIONS.remove(userDto.toString());
        log.debug("session group size {} ", ALL_USER_SESSIONS.size());
    }

    public static Collection<Session> getAllUserSession() {
        return ALL_USER_SESSIONS.sessions();
    }

    // 系统session相关的方法

    public static void addSystemSession(int systemId, Session session) {
        // 判断是否有已经在线的session,挤下线
        Session s = getSystemSession(systemId);
        if (s != null) {
            Message logoutMessage = new Message(MessageId.SYS_KICK_SYS_OFFLINE.id);
            s.sendMessageAndClose(logoutMessage);
            removeSystemSession(systemId);
        }
        ALL_SYSTEM_SESSIONS.add(systemId, session);
    }

    public static Session getSystemSession(int systemId) {
        return ALL_SYSTEM_SESSIONS.get(systemId);
    }

    public static void removeSystemSession(int systemId) {
        ALL_SYSTEM_SESSIONS.remove(systemId);
    }

    /**
     * 维护repeater的session
     * repeaterId使用ip+port标识一个repeater实例(兼容单台服务器多个实例的情况)
     * 绑定的端口是nacos的端口, 即http服务端口, 与netty端口不一致
     *
     * @param repeaterId 实例ip
     * @param session    连接
     */
    public static void addRepeaterSession(String repeaterId, Session session) {

        // 判断是否有已经在线的session,挤下线
        Session s = getRepeaterSession(repeaterId);
        if (s != null) {
            Message logoutMessage = new Message(MessageId.SYS_KICK_SYS_OFFLINE.id);
            s.sendMessageAndClose(logoutMessage);
            removeRepeaterSession(repeaterId);
        }
        ALL_REPEATER_SESSIONS.add(repeaterId, session);

    }

    public static Session getRepeaterSession(String repeaterId) {
        return ALL_REPEATER_SESSIONS.get(repeaterId);
    }

    public static void removeRepeaterSession(String repeaterId) {
        ALL_REPEATER_SESSIONS.remove(repeaterId);
    }

    public static int countRepeaterSession() {
        return ALL_REPEATER_SESSIONS.size();
    }

}
